import { AttributeTabKey, PropertyKey, NumberStatus } from "@/constants/Enums";
import { MetaclassType } from "@/constants/MetaclassType";
import { modelService } from "@/modules/model/service";
import { locale } from "@/util/locale";
import { NumberPartInfo, NumberSchemeDto, PropertyDropdownOption } from "../types";

import { PaneModel } from "./PaneModel";
import { getUid, sleep } from "@/util/common";
import { ApiCode } from "@/constants/api";

const sequenceTypeMap = {
  // eslint-disable-next-line camelcase
  SequenceType_Numeric: "数字",
  // eslint-disable-next-line camelcase
  SequenceType_Separator: "分隔符",
  // eslint-disable-next-line camelcase
  SequenceType_Character: "字母",
  // eslint-disable-next-line camelcase
  SequenceType_OwnerNumber: "所有者编号",
  // eslint-disable-next-line camelcase
  SequenceType_Expression: "表达式"
};

export class NumberPartModel extends PaneModel {
  tableData: NumberPartInfo[] = [];
  sequenceTypeOptions: PropertyDropdownOption[] = [];
  currentRow: NumberPartInfo | undefined;
  currentIndex = -1;
  curModelId = "";

  async loadNumberParts() {
    const { projectId, modelId } = this.tabsModel.data;

    if (!projectId || !modelId) return;
    this.loaded = false;
    try {
      const res = await modelService.queryNumberParts({ projectId, instanceId: modelId });
      this.curModelId = modelId;
      this.tableData = [];
      // bugfix: 返回页面可能延迟
      if (this.tabsModel.data.activeTab !== AttributeTabKey.NumberPart) {
        this.tabsModel.data.activeTab = AttributeTabKey.NumberPart;
      }
      if (res?.length) {
        for (let row of res) {
          let { instanceId, nameConfig, sequenceConfig, initialValueConfig } = row;
          this.tableData.push({
            id: getUid(),
            instanceId,
            name: nameConfig?.value,
            sequenceType: sequenceConfig?.value,
            initialValue: initialValueConfig?.value
          });
        }
      }
    } catch (error) {
      this.tableData = [];
      error && console.error(error);
    } finally {
      this.loaded = true;
    }
  }

  async loadDataWhenNotLoad() {
    if (!this.loaded || this.tabsModel.data.modelId !== this.curModelId) {
      this.fresh();
    }
  }

  async fresh() {
    await this.loadNumberParts();
    this.sequenceTypeOptions = await modelService.getPropertyItems(
      this.tabsModel.data.projectId!,
      this.tabsModel.data.modelId!,
      PropertyKey.NumberPart_sequence
    );
  }

  async clear() {}

  async navToPropertyPane(row: NumberPartInfo) {
    if (!row.instanceId) {
      app.$notify({
        type: "warning",
        message: locale.t(`请先保存数据`),
        title: "提示"
      });
      return;
    }
    const { projectId, modelId } = this.tabsModel.data;
    if (!projectId || !modelId) return;
    const query = {
      projectId,
      modelId: row.instanceId,
      metaclass: MetaclassType.Property,
      activeKey: AttributeTabKey.Properties,
      redirectModelId: modelId
    };
    app.$router.push({ path: "/ipcWindow/ModelDetailWindow", query });
  }

  async handleRowClick(row: NumberPartInfo) {
    this.currentIndex = this.tableData.findIndex(v => v.name === row.name);
    if (this.currentIndex !== -1) this.currentRow = this.tableData[this.currentIndex];
  }

  // 更改编号名称
  changeName(val: string, index: number) {
    console.error(val);

    const isExistName = this.tableData.some((ta, idx) => ta.name === val && idx !== index);
    if (isExistName) {
      app.$notify({
        type: "warning",
        message: locale.t(`名称不能重复`),
        title: "提示"
      });
      this.tableData[index].name = "";
      return;
    }
    this.tableData[index].name = val;
    if (!this.tableData[index].status) {
      this.tableData[index].status = NumberStatus.UPDATE;
    }
  }

  // 更改初始值
  changeValue(val: string, index: number) {
    if (!this.tableData[index].sequenceType) {
      app.$notify({
        type: "warning",
        message: locale.t(`请先选择编号类型`),
        title: "提示"
      });
      return;
    }
    switch (this.tableData[index].sequenceType) {
      case "SequenceType_Numeric":
        if (val && !/^\d+$/.test(val)) {
          app.$notify({
            type: "warning",
            message: locale.t(`初始值只能为数字`),
            title: "提示"
          });
          val = "";
        }
        break;
      case "SequenceType_Character":
        if (val && !/^[a-zA-Z]+$/.test(val)) {
          app.$notify({
            type: "warning",
            message: locale.t(`初始值只能为字母`),
            title: "提示"
          });
          val = "";
        }
        break;
      case "SequenceType_Separator":
        if (val && !/^[^\s\d a-zA-Z]+$/.test(val)) {
          app.$notify({
            type: "warning",
            message: locale.t(`初始值不能包含空格、数字、字母`),
            title: "提示"
          });
          val = "";
        }
        break;
      default:
        break;
    }
    this.tableData[index].initialValue = val;
    if (!this.tableData[index].status) {
      this.tableData[index].status = NumberStatus.UPDATE;
    }
  }

  // 更新编号类型
  handleChangeSequenceType(type: string, index: number) {
    this.tableData[index].sequenceType = type;
    // 更新类型后需要将初始值清除
    this.tableData[index].initialValue = "";
    if (!this.tableData[index].status) {
      this.tableData[index].status = NumberStatus.UPDATE;
    }
  }

  async addNewRow() {
    const { modelId, projectId } = this.tabsModel.data;
    if (!modelId || !projectId) return;
    let nameIndex = 0;
    this.tableData.forEach(item => {
      if (item.name.indexOf("编号属性") == 0) {
        const num = item.name.match(/\d+/g);
        if (num) {
          nameIndex = nameIndex > Number(num[0]) ? nameIndex : Number(num[0]) + 1;
        } else {
          nameIndex++;
        }
      }
    });
    const uuid = getUid();
    this.tableData.push({
      id: uuid,
      instanceId: "",
      name: nameIndex > 0 ? `编号属性${nameIndex}` : "编号属性",
      sequenceType: "",
      initialValue: "",
      status: NumberStatus.ADD
    });
    this.currentIndex = this.tableData.length - 1;
    this.currentRow = this.tableData[this.currentIndex];
    return uuid;
  }

  // up 上移 down 下移
  async moveRow(direction: string) {
    const { projectId } = this.tabsModel.data;
    if (!this.currentRow || !projectId || this.currentIndex === -1) return;
    if (direction === "up") {
      if (this.currentIndex === 0) return;
      const itemToMove = this.tableData.splice(this.currentIndex, 1)[0];
      this.tableData.splice(this.currentIndex - 1, 0, itemToMove);
      this.currentIndex = this.currentIndex - 1;
    } else if (direction === "down") {
      if (this.currentIndex === this.tableData.length - 1) return;
      const itemToMove = this.tableData.splice(this.currentIndex, 1)[0];
      this.tableData.splice(this.currentIndex + 1, 0, itemToMove);
      this.currentIndex = this.currentIndex + 1;
    }
    this.currentRow = this.tableData[this.currentIndex];
  }

  async cloneRow() {
    const { projectId } = this.tabsModel.data;
    if (!this.currentRow || !projectId) return;
    let name = this.currentRow.name;
    if (/\d$/.test(name)) {
      //  如果名称以数字结尾
      name = name.replace(/(\d+)$/, "");
    }
    let nameIndex = 0;
    this.tableData.forEach(item => {
      if (item.name.indexOf(name) == 0) {
        const num = item.name.match(/\d+/g);
        if (num) {
          nameIndex = nameIndex > Number(num[0]) ? nameIndex : Number(num[0]) + 1;
        } else {
          nameIndex++;
        }
      }
    });
    const uuid = getUid();
    this.tableData.push({
      id: uuid,
      instanceId: "",
      name: nameIndex > 0 ? `${name}${nameIndex}` : name,
      sequenceType: this.currentRow.sequenceType,
      initialValue: this.currentRow.initialValue,
      status: NumberStatus.ADD
    });
    this.currentIndex = this.tableData.length - 1;
    this.currentRow = this.tableData[this.currentIndex];
    return uuid;
  }

  async deleteRow() {
    if (!this.currentRow) return;
    this.tableData[this.currentIndex].status = NumberStatus.DELETE;
    this.currentIndex = -1;
    this.currentRow = undefined;
  }

  // numberPart顺序校验
  valiadNumberPartList() {
    if (!this.tableData.length) return true;

    const filterTable = this.tableData.filter(ta => ta.status !== NumberStatus.DELETE).map(v => v.sequenceType || "");

    if (filterTable.some(v => v === "")) {
      app.$notify({
        type: "warning",
        message: locale.t(`编号类型不允许为空`),
        title: "编号属性设置有误"
      });
      return false;
    }

    if (filterTable[0] === "SequenceType_Separator" || filterTable.last() === "SequenceType_Separator") {
      app.$notify({
        type: "warning",
        message: locale.t(`首位与末尾的编号属性的类型不能为分隔符`),
        title: "编号属性设置有误"
      });
      return false;
    }

    const allowedNextTypes = {
      // eslint-disable-next-line camelcase
      SequenceType_Numeric: ["SequenceType_Separator"],
      // eslint-disable-next-line camelcase
      SequenceType_Separator: ["SequenceType_Numeric", "SequenceType_Character"],
      // eslint-disable-next-line camelcase
      SequenceType_Character: ["SequenceType_Separator"]
    };

    let currType: Set<string> = new Set();
    const isValid = filterTable.every((item, index) => {
      if (index > 0) {
        const currentType = item;
        const prevType = filterTable[index - 1];
        const valid = allowedNextTypes[prevType].includes(currentType);
        if (!valid) {
          currType.add(prevType);
          currType.add(currentType);
          return false;
        }
      }
      return true;
    });

    if (!isValid) {
      let tempCurrType = Array.from(currType)
        .map(item => sequenceTypeMap[item])
        .join("、");
      app.$notify({
        type: "warning",
        message: locale.t(`类型为${tempCurrType}的编号属性必须和其他类型的编号属性交替排列`),
        title: "编号属性设置有误"
      });
      return false;
    }
    return true;
  }

  // 保存编号方案
  async saveNumberingScheme(isClose = false) {
    // 校验规则是否编辑过，编辑过则提示保存
    if (this.tableData.some(ta => [NumberStatus.ADD, NumberStatus.DELETE, NumberStatus.UPDATE].includes(ta.status as NumberStatus))) {
      const res = await app.$confirm
        .popup({
          title: "编号属性设置",
          subTitle: "数据有更改，是否保存？",
          content: "数据有更改，不保存则数据会丢失",
          showCheckbox: false,
          status: "warn",
          okText: "是",
          cancelText: "否"
        })
        .catch(() => {
          return true;
        });
      if (res.type === "ok") {
        const valid = this.valiadNumberPartList();
        if (!valid) return false;
        await this.saveData();
        await sleep(0.5);
        if (isClose) {
          return true;
        }
      } else {
        return true;
      }
    } else {
      return true;
    }
  }

  async saveNumberRule() {
    const valid = this.valiadNumberPartList();
    if (!valid) return false;
    await this.saveData();
  }

  async saveData() {
    const { projectId, modelId } = this.tabsModel.data;
    const numberSchemeDto: NumberSchemeDto = {
      projectId: projectId!,
      parentId: modelId!,
      numberPartOperationInfos: this.tableData
        .filter(ta => !(ta.status === NumberStatus.DELETE && !ta.instanceId))
        .map(ta => {
          return {
            instanceId: ta.instanceId || "",
            name: ta.name,
            sequenceType: ta.sequenceType,
            initialValue: ta.initialValue,
            status: ta.status || ""
          };
        })
    };
    const res = await modelService.saveNumberScheme(numberSchemeDto);
    if (res.code === ApiCode.SUCCESS) {
      this.tableData.forEach(ta => (ta.status = null));
      app.$notify({
        type: "success",
        message: locale.t(`保存成功`),
        title: "提示"
      });
    }
    this.loaded = false;
    await this.loadDataWhenNotLoad(); // 保存完再重新查一遍
  }
}
